﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using System.Data.Linq.SqlClient;

namespace Domzs.Extensions
{
    public static class QueryableExtensions
    {
        public static IQueryable<T> Like<T>(this IQueryable<T> source, string propertyName, string keyword)
        {
            Type type = typeof(T);
            PropertyInfo property = type.GetProperty(propertyName);
            ParameterExpression expression = Expression.Parameter(type, "p");
            MemberExpression expression2 = Expression.MakeMemberAccess(expression, property);
            ConstantExpression expression3 = null;
            if (keyword.IndexOf("*") == -1)
            {
                expression3 = Expression.Constant(keyword + "%");
            }
            else
            {
                expression3 = Expression.Constant(keyword.Replace("*", "%"));
            }
            MethodInfo method = typeof(SqlMethods).GetMethod("Like", new Type[] { typeof(string), typeof(string) });
            Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(Expression.Call(null, method, new Expression[] { expression2, expression3 }), new ParameterExpression[] { expression });
            return source.Where<T>(predicate);
        }

        public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName, bool asc)
        {
            Type type = typeof(T);
            string methodName = asc ? "OrderBy" : "OrderByDescending";
            PropertyInfo property = type.GetProperty(propertyName);
            ParameterExpression expression = Expression.Parameter(type, "p");
            LambdaExpression expression3 = Expression.Lambda(Expression.MakeMemberAccess(expression, property), new ParameterExpression[] { expression });
            MethodCallExpression expression4 = Expression.Call(typeof(Queryable), methodName, new Type[] { type, property.PropertyType }, new Expression[] { source.Expression, Expression.Quote(expression3) });
            return source.Provider.CreateQuery<T>(expression4);
        }

        public static IQueryable<TSource> WhereIn<TSource, TKey>(this IQueryable<TSource> source1, Expression<Func<TSource, TKey>> keySelector, IEnumerable<TKey> source2)
        {
            if (source1 == null)
            {
                throw new ArgumentNullException("source1");
            }
            if (keySelector == null)
            {
                throw new ArgumentNullException("keySelector");
            }
            if (source2 == null)
            {
                throw new ArgumentNullException("source2");
            }
            Expression left = null;
            foreach (TKey local in source2)
            {
                Expression right = Expression.Equal(keySelector.Body, Expression.Constant(local, typeof(TKey)));
                if (left == null)
                {
                    left = right;
                }
                else
                {
                    left = Expression.OrElse(left, right);
                }
            }
            return source1.Where<TSource>(Expression.Lambda<Func<TSource, bool>>(left, keySelector.Parameters));
        }
    }
}
